package com.citcc.api.controller;

import com.alipay.api.internal.util.AlipaySignature;
import com.citcc.api.utils.WeiXinPayUtil;
import com.citcc.business.bean.CdzAccountAmount;
import com.citcc.business.bean.CdzAmountDetail;
import com.citcc.business.mapper.CdzAccountAmountMapper;
import com.citcc.business.mapper.CdzAmountDetailMapper;
import com.citcc.business.util.IdGenerator;
import com.citcc.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by czh on 2019/5/21 0021 16:08
 */
@RestController
@RequestMapping("/paymentNotify")
public class PaymentNotifyController {

    private Logger log = LoggerFactory.getLogger(PaymentNotifyController.class);

    @Autowired
    private CdzAccountAmountMapper accountAmountMapper;
    @Autowired
    private CdzAmountDetailMapper amountDetailMapper;

    @Value("${pay.zhifubao.apppay.privateKey}")
    private String privateKey;
    @Value("${pay.zhifubao.apppay.publicKey}")
    private String publicKey;
    @Value("${pay.zhifubao.apppay.appid}")
    private String appId;
    @Value("${pay.zhifubao.apppay.requesturl}")
    private String requestUrl;

    /**
     * 微信支付回调
     *
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/weixin/notify",
            produces = MediaType.APPLICATION_JSON_VALUE)
    public String depostwxpaySucc(HttpServletRequest request) throws IOException {

        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }

        Map<String, String> params;
        try {
            String resultXml = new String(outSteam.toByteArray(), "utf-8");
            params = WeiXinPayUtil.xmlToMap(resultXml);
        } catch (Exception e) {
            return "FAIL";
        }
        outSteam.close();
        inStream.close();

        if (!WeiXinPayUtil.isTenpaySign(params)) log.error("微信支付回调验签失败！");

        if (StringUtils.equals("SUCCESS", params.get("return_code")) && StringUtils.equals("SUCCESS", params.get("result_code"))) {
            // 商户订单号
            String outTradeNo = params.get("out_trade_no");
            // 总金额
            String totalFee = params.get("total_fee");
            // 微信支付订单号（交易流水号）
            String tradeNo = params.get("transaction_id");
            // 处理业务逻辑
            if (paymentBusiness(outTradeNo, String.valueOf(new BigDecimal(totalFee).divide(new BigDecimal(100))), tradeNo, "1"))
                return "SUCCESS";
        }
        return "FAIL";
    }

    /**
     * 支付宝支付回调
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/alipay/notify", method = {RequestMethod.POST, RequestMethod.GET})
    public String notify(HttpServletRequest request) throws Exception {

        Map<String, String> params = new HashMap<>();
        // 1.从支付宝回调的request域中取值
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = iter.next();
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        // 2.封装必须参数
        // 商户订单号
        String outTradeNo = request.getParameter("out_trade_no");
        // 交易状态
        String tradeStatus = request.getParameter("trade_status");
        // 交易金额
        String totalAmount = request.getParameter("total_amount");
        // 支付宝交易号（交易流水号）
        String tradeNo = request.getParameter("trade_no");

        if (!AlipaySignature.rsaCheckV1(params, publicKey, "utf-8", "RSA2")) log.error("支付宝支付回调验签失败");

        // 处理业务逻辑
        if ("TRADE_SUCCESS".equals(tradeStatus) && paymentBusiness(outTradeNo, totalAmount, tradeNo, "0"))
            return "success";
        return "fail";
    }

    /**
     * 支付成功处理业务逻辑
     *
     * @param outTradeNo  商户订单号
     * @param totalAmount 交易金额
     * @param tradeNo     交易流水号
     * @param payType     支付类型 0-支付宝 1-微信
     */
    public Boolean paymentBusiness(String outTradeNo, String totalAmount, String tradeNo, String payType) {

        // 更改充值记录状态
        CdzAmountDetail cdzAmountDetail = amountDetailMapper.selectByPrimaryKey(outTradeNo);
        if (cdzAmountDetail == null || !StringUtils.equals("1", cdzAmountDetail.getType())
                || !StringUtils.equals(payType, cdzAmountDetail.getPayType()) || !StringUtils.equals("1", cdzAmountDetail.getPayState())
                || cdzAmountDetail.getAmount().compareTo(new BigDecimal(totalAmount)) != 0) return false;

        // 用户ID
        String userId = cdzAmountDetail.getUserId();

        CdzAmountDetail cdzAmount = new CdzAmountDetail();
        cdzAmount.setId(outTradeNo);
        cdzAmount.setPayState("2");
        cdzAmount.setPayTime(new Date());
        cdzAmount.setTradeNo(tradeNo);
        cdzAmount.setPayMessage("充值成功");
        cdzAmount.setUpdateTime(new Date());
        cdzAmount.setUpdateBy(userId);
        amountDetailMapper.updateByPrimaryKeySelective(cdzAmount);

        // 更新账户余额
        CdzAccountAmount accountAmount = accountAmountMapper.selectByUserId(userId);
        CdzAccountAmount amount;
        if (accountAmount != null) {
            amount = new CdzAccountAmount();
            amount.setId(accountAmount.getId());
            amount.setTotalAmount(accountAmount.getTotalAmount().add(new BigDecimal(totalAmount)));
            if (StringUtils.equals("1", accountAmount.getFrozenFlag())) {
                amount.setAvailableAmount(amount.getTotalAmount().subtract(accountAmount.getFrozenAmount()));
            } else {
                amount.setAvailableAmount(amount.getTotalAmount());
            }
            amount.setUpdateTime(new Date());
            amount.setUpdateBy(userId);
            accountAmountMapper.updateByPrimaryKeySelective(amount);
        } else {
            amount = new CdzAccountAmount();
            amount.setId(IdGenerator.generateId());
            amount.setUserId(userId);
            amount.setTotalAmount(new BigDecimal(totalAmount));
            amount.setAvailableAmount(new BigDecimal(totalAmount));
            amount.setFrozenFlag("0");
            amount.setCreateTime(new Date());
            amount.setCreateBy(userId);
            amount.setUpdateTime(amount.getCreateTime());
            amount.setUpdateBy(userId);
            amount.setDelFlag("0");
            accountAmountMapper.insertSelective(amount);
        }
        return true;
    }
}